#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "rawivfileplugin.h"
#include "../../data/bio.h"
#include "../../data/reg3dvolumedata.h"

using namespace PBVP;
RawIVFilePlugin::RawIVFilePlugin()
{
}

RawIVFilePlugin::~RawIVFilePlugin()
{
}

void RawIVFilePlugin::initialize(MainInterface* pMainInterface)
{
	// do nothing now
}

DataInterface* RawIVFilePlugin::loadFile(const QString &fname)
{
	if (!fname.endsWith(".rawiv"))
	{
		return NULL;
	}

	int nverts, ncells;
	float minext[3], maxext[3];
	unsigned int dim[3];
	float orig[3], span[3];

	// determine file data type
	struct stat filestat;
	if (stat(fname.toAscii().data(), &filestat) < 0) {
		fprintf(stderr, "cannot find data file\n");
		return NULL;
	}
	int sz = filestat.st_size;

	BinaryIO *pio = new BinaryIO(fname.toAscii().data());
	if(!pio->open()) {
		fprintf(stderr, "Data File Open Failed\n");
		return NULL;
	}
	pio->get(minext, 3);
	pio->get(maxext, 3);
	pio->get(&nverts, 1);
	pio->get(&ncells, 1);
	pio->get(dim, 3);
	pio->get(orig, 3);
	pio->get(span, 3);

	Reg3DVolumeData *pReg3Data = new Reg3DVolumeData(dim);
	pReg3Data->setNumOfVariables(1);
	nverts = dim[0]*dim[1]*dim[2];
	// rawiv header is 68 bytes
	int unit_size = (sz - 68) / nverts;
	switch (unit_size) {
	case 1:
		{
			unsigned char* data = new unsigned char[nverts];
			pio->get(data, nverts);
			pReg3Data->setDataArray(data, 0, UCHAR_TYPE);
		}
		break;
	case 2:
		{
			unsigned short* data = new unsigned short[nverts];
			pio->get(data, nverts);
			pReg3Data->setDataArray(data, 0, USHORT_TYPE);
		}
		break;
	case 4:
		{
			float* data = new float[nverts];
			pio->get(data, nverts);
			pReg3Data->setDataArray(data, 0, FLOAT_TYPE);
		}
		break;
	case 8:
		{
			double* data = new double[nverts];
			pio->get(data, nverts);
			pReg3Data->setDataArray(data, 0, DOUBLE_TYPE);
		}
		break;
	default:
		fprintf(stderr, "Type Error in Rawiv File\n");
		delete pReg3Data;
		return NULL;
	}

	pReg3Data->setOrigin(orig);
	pReg3Data->setSpan(span);
#ifdef _DEBUG
	printf("dim: %d %d %d\n", dim[0], dim[1], dim[2]);
	printf("span: %f %f %f\n", span[0], span[1], span[2]);
#endif

	pio->close();
	delete pio;

	return pReg3Data;
}

bool RawIVFilePlugin::saveFile(DataInterface* pData, const QString &fname)
{
#ifdef __GNU__
	Reg3DVolumeData *pReg3Data = NULL;
	if(pData->getDataSetType() == VOLUME_DATA) pReg3Data = (Reg3DVolumeData *)(pData);
#else
	Reg3DVolumeData *pReg3Data = dynamic_cast<Reg3DVolumeData *>(pData);
#endif
	if(!pReg3Data) {
		fprintf(stderr, "Not a 3D Regular Volumetric Data\n");
		return false;
	}
	BinaryIO *pout = new BinaryIO(fname.toAscii().data(), BinaryIO::WRITE);
	if(!pout->open()) {
		fprintf(stderr, "Cannot Open File %s for Writing\n", fname.toAscii().data());
		return false;
	}

	int nverts, ncells;
	float minext[3], maxext[3];
	unsigned int dim[3];
	float orig[3], span[3];

	pReg3Data->getMinMaxExt(minext, maxext);
	pout->put(minext, 3);
	pout->put(maxext, 3);
	nverts = pReg3Data->numOfVerts();
	ncells = pReg3Data->numOfCells();
	pout->put(&nverts, 1);
	pout->put(&ncells, 1);
	pReg3Data->getDimension(dim);
	pReg3Data->getOrigin(orig);
	pReg3Data->getSpan(span);
	pout->put(dim, 3);
	pout->put(orig, 3);
	pout->put(span, 3);

	DataPtr data = pReg3Data->getDataPtr();
	switch(pReg3Data->getDataType()) {
	case UCHAR_TYPE:
		pout->put(data.uchar_ptr, nverts);
		break;
	case USHORT_TYPE:
		pout->put(data.ushort_ptr, nverts);
		break;
	case INT_TYPE:
		pout->put(data.int_ptr, nverts);
		break;
	case FLOAT_TYPE:
		pout->put(data.float_ptr, nverts);
		break;
	case DOUBLE_TYPE:
		pout->put(data.double_ptr, nverts);
		break;
	}
	pout->close();
	delete pout;

	return true;
}

Q_EXPORT_PLUGIN2(rawivfile, RawIVFilePlugin)
